// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_CODE_TRACER_H_
#define V8_CODE_TRACER_H_

#include "src/allocation.h"
#include "src/flags.h"
#include "src/globals.h"
#include "src/utils.h"
#include "src/vector.h"

namespace v8 {
namespace internal {

    class CodeTracer final : public Malloced {
    public:
        explicit CodeTracer(int isolate_id)
            : file_(nullptr)
            , scope_depth_(0)
        {
            if (!ShouldRedirect()) {
                file_ = stdout;
                return;
            }

            if (FLAG_redirect_code_traces_to != nullptr) {
                StrNCpy(filename_, FLAG_redirect_code_traces_to, filename_.length());
            } else if (isolate_id >= 0) {
                SNPrintF(filename_, "code-%d-%d.asm", base::OS::GetCurrentProcessId(),
                    isolate_id);
            } else {
                SNPrintF(filename_, "code-%d.asm", base::OS::GetCurrentProcessId());
            }

            WriteChars(filename_.start(), "", 0, false);
        }

        class Scope {
        public:
            explicit Scope(CodeTracer* tracer)
                : tracer_(tracer)
            {
                tracer->OpenFile();
            }
            ~Scope() { tracer_->CloseFile(); }

            FILE* file() const { return tracer_->file(); }

        private:
            CodeTracer* tracer_;
        };

        void OpenFile()
        {
            if (!ShouldRedirect()) {
                return;
            }

            if (file_ == nullptr) {
                file_ = base::OS::FOpen(filename_.start(), "ab");
            }

            scope_depth_++;
        }

        void CloseFile()
        {
            if (!ShouldRedirect()) {
                return;
            }

            if (--scope_depth_ == 0) {
                fclose(file_);
                file_ = nullptr;
            }
        }

        FILE* file() const { return file_; }

    private:
        static bool ShouldRedirect() { return FLAG_redirect_code_traces; }

        EmbeddedVector<char, 128> filename_;
        FILE* file_;
        int scope_depth_;
    };

} // namespace internal
} // namespace v8

#endif // V8_CODE_TRACER_H_
